package ccore

import (
	"encoding/csv"
	"fmt"
	"io"
	"ll_csv_con/cutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

var (
	csvRecordChan       chan []string //csv 的原始数据（行）
	targetIndex         int           //我们的目标的所属的列 下标（索引）
	NewFileName         string
	wg                  sync.WaitGroup
	filterCsvRecordChan chan []string //csv 过滤了条件的数据（行）
)

func init() {
	csvRecordChan = make(chan []string, 10)
	filterCsvRecordChan = make(chan []string, 10)
}

/**
 * 筛选出字段值
 */
func Sx(csvpath string, target string, key string, icase string) {
	//读取数据，生成文件
	wg.Add(1)
	go readCsv(csvpath, target)

	//过滤
	wg.Add(1)
	go pushSxDaTata(target, key, icase)

	//输出
	wg.Add(1)
	go writeCsvChan()

	wg.Wait()
	println(NewFileName + "文件已经生成成功，请查阅")
}

//结果写入新的文件
func writeCsvChan() {
	time.Sleep(time.Second)
	nfs, err := os.OpenFile(NewFileName, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		log.Fatalf("writeCsvChan can not create file, err is %+v , FILENAME IS %+v", err, NewFileName)
	}
	defer nfs.Close()
	nfs.Seek(0, io.SeekEnd)

	w := csv.NewWriter(nfs)
	//设置属性
	w.Comma = ','
	w.UseCRLF = true

	for {
		if cv, ok := <-filterCsvRecordChan; ok {
			//写入文件
			err = w.Write(cv)
			if err != nil {
				log.Fatalf("can not write, err is %+v", err)
			}
			//这里必须刷新，才能将数据写入文件。
			w.Flush()
		} else {
			break
		}
	}
	wg.Done()
}

/**
 * 过滤条件
 */
func pushSxDaTata(target string, key string, icase string) {
	//场景：读channel，但不确定channel是否关闭时
	//原理：读已关闭的channel会得到零值，如果不确定channel，需要使用ok进行检测。ok的结果和
	for {
		if cv, ok := <-csvRecordChan; ok {
			var s, sstr string
			if icase == "yes" {
				s = strings.ToUpper(cv[targetIndex])
				sstr = strings.ToUpper(key)
			} else {
				s = cv[targetIndex]
				sstr = key
			}
			//过滤数据,包含的话，进入下一轮
			if strings.Contains(s, sstr) {
				filterCsvRecordChan <- cv
			}
		} else {
			break
		}
	}
	close(filterCsvRecordChan)
	wg.Done()
}

func readCsv(csvpath string, target string) {
	//获取新的名字
	if NewFileName == "" {
		NewFileName = GetNewFilename(csvpath)
	}
	//如果文件存在，删除
	if cutil.CheckFileIsExist(NewFileName) {
		err := os.Remove(NewFileName)
		if err != nil {
			// 删除失败
			log.Fatalln("Couldn't delete the NewFileName file", err)
		}
	}
	csvfile, err := os.Open(csvpath)
	if err != nil {
		log.Fatalln("Couldn't open the csv file", err)
	}
	defer csvfile.Close()

	// Parse the file
	r := csv.NewReader(csvfile)
	isfisrt := true
	// Iterate through the records
	for {

		// Read each record from csv
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		//首行特殊处理
		if isfisrt {
			//获取目标的索引
			ti := getTargetIndex(record, target)
			targetIndex = ti
			if targetIndex == -1 {
				fmt.Println("没有这个目标列" + target)
				os.Exit(0)
			}
			isfisrt = false
			//首行直接写入新文件
			writeCsv(NewFileName, record)
			continue
		}
		csvRecordChan <- record
	}
	wg.Done()
	close(csvRecordChan)
}

//写入一行
func writeCsv(NewFileName string, newData []string) {
	//这样可以追加写
	nfs, err := os.OpenFile(NewFileName, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		log.Fatalf("can not create file, err is %+v", err)
	}
	defer nfs.Close()
	nfs.Seek(0, io.SeekEnd)

	w := csv.NewWriter(nfs)
	//设置属性
	w.Comma = ','
	w.UseCRLF = true
	err = w.Write(newData)
	if err != nil {
		log.Fatalf("can not write, err is %+v", err)
	}
	//这里必须刷新，才能将数据写入文件。
	w.Flush()
}

//获取目标筛选target 的下标
func getTargetIndex(firstRecord []string, target string) int {
	ti := -1
	for i, v := range firstRecord {
		if v == target {
			ti = i
		}
	}
	return ti
}

func GetNewFilename(oldName string) string {
	paths, filename := filepath.Split(oldName)
	filenameWithSuffix := path.Base(oldName)                 //获取文件名带后缀
	fileSuffix := path.Ext(filenameWithSuffix)               //获取文件后缀
	filenameOnly := strings.TrimSuffix(filename, fileSuffix) //获取文件名
	return paths + filenameOnly + "_new_sx" + ".csv"
}
